Philosophy is an important study that provides us with valuable skills in life. It produces better critical thinkers, more creative thinkers, and better communicators. Despite one’s knowledge of philosophy, this analysis aims to give all levels of audience a general picture of philosophy from a new perspective, using text mining and data visualizations from the History of Philosophy dataset. The dataset contains over 300,000 sentences from over 50 texts spanning 13 major schools of philosophy. The represented schools are: Plato, Aristotle, Stoicism, Rationalism, Empiricism, German Idealism, Nietzsche, Communism, Capitalism, Phenomenology, Continental, Analytic, and Feminism. Sentences are units of analysis for this project. We will first take a look at the text used in each school of thought, examine the trend in philosophical speech over time, conduct a sentiment analysis, and finally compare the similarity in phisophical text among different schools. Without further ado, let’s dive in!
library(beeswarm)
library(data.table)
library(dichromat)
library(dplyr)
library(factoextra)
library(fmsb)
library(ggplot2)
library(gridExtra)
library(qdap)
library(quanteda)
library(quanteda.textstats)
library(RANN)
library(RColorBrewer)
library(readtext)
library(rvest)
library(scales)
library(sentimentr)
library(stopwords)
library(stringr)
library(syuzhet)
library(textreuse)
library(tibble)
library(tidytext)
library(tidyverse)
library(tm)
library(topicmodels)
library(wesanderson)
library(wordcloud)
source("../lib/plot_stacked.R")
source("../lib/speech_funcs.R")
source("../lib/helper_funcs.R")
# df <- read.csv("../data/philosophy_data.csv")
# Read data using data.table to decrease runtime
df <- data.table::fread("../output/philosophy_data_table.csv")
df <- df %>%
group_by(school) %>%
mutate(mode_date = find_mode(original_publication_date)) %>%
ungroup() %>%
mutate(school = ifelse(school == "german_idealism", "German Idealism", str_to_title(school)),
school_ordered = reorder(factor(school), mode_date, mean, order = TRUE))
palette <- get_palette(length(unique(df$school)))
What is the main philosophy in each school of thought?
For those who have never studied philosophy, or even if you only know Plato and Aristotle, you might start wondering what the other major schools of thought are and what the main idea of phisolophy is behind each school. To answer those questions, I have constructed a series of wordclouds and looked at the most used bigrams by each school from the philosophy text in our data.
par(mfrow = c(4, 4))
i <- 0
for(s in levels(df$school_ordered)) {
docs <- Corpus(VectorSource(df[df$school == s, ]$sentence_str)) %>%
tm_map(tolower) %>%
tm_map(removePunctuation) %>%
tm_map(removeNumbers) %>%
tm_map(removeWords, stopwords("english")) %>%
tm_map(stripWhitespace)
tdm <- TermDocumentMatrix(docs)
tdm_tidy <- tidy(tdm)
tdm_overall <- summarise(group_by(tdm_tidy, term), sum(count))
i <- i + 1
plt_title <- s
wordcloud(tdm_overall$term, tdm_overall$`sum(count)`,
scale = c(5, 0.5),
max.words = 200,
min.freq = 1,
random.order = FALSE,
rot.per = 0.3,
random.color = FALSE,
colors = palette[i])
mtext(plt_title, side = 3)
}

Wordclouds are visual representations of words that give greater prominence to words that appear more frequently. Here, I created a wordcloud of the words most used by the philosophers belonging to each school of thought. Looking at the wordclouds, we can see that there are two types of schools: one frequently used content words relevant to their philosophies and the other frequenly used function words only. For example, Capitalism, Communism, and Feminism are schools that used very descriptive words in their philosophy texts and one could infer the main theme employed by each school:
- Capitalism focuses on “price”, “money”, and “value” as it describes an economic and political system in which a country’s trade and industry are controlled by private owners for profit, rather than by the state
- Communism places emphasis on “labour”, “production”, and “workers” as it describes a society in which all property is publicly owned and each person works and is paid according to their abilities and needs
- Feminism is centered around women’s rights as reflected in the use of words such as “women”, “girl”, “wife”, and possiblly racial discrimination through the use of words such as “black” and “white”
On the other hand, Plato, Aristotle, Rationalism, or Empiricism are schools that didn’t seem to use many descriptive words that represent their philosphies as we mostly see “one”, “will”, “can”, “ideas” in their texts. It could be explained by the fact that these are the schools of thoughts that are older and tend to be more abstract. Specifically, Stoicism’s texts were heavily written in old English, which makes it more difficult to understand and infer what the main theme is behind their philosphy.
df %>%
unnest_tokens(bigram, sentence_str, token = "ngrams", n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% stopwords::stopwords(source = "snowball")) %>%
filter(!word2 %in% stopwords::stopwords(source = "snowball")) %>%
filter(!is.na(word1)) %>%
filter(!is.na(word2)) %>%
unite(bigram, word1, word2, sep = " ") %>%
group_by(school_ordered, bigram) %>%
summarize(n_bigram = n()) %>%
slice_max(n_bigram, n = 10) %>%
mutate(bigram = reorder_within(bigram, n_bigram, school_ordered)) %>%
ggplot(aes(x = bigram, y = n_bigram, fill = school_ordered)) +
geom_bar(stat = "identity", show.legend = FALSE) +
facet_wrap(~school_ordered, scales = "free") +
coord_flip() +
scale_x_reordered() +
scale_fill_manual(values = get_palette(length(unique(df$school)))) +
labs(title = "Top 10 Bigrams by School", x = element_blank(), y = "Count") +
theme_classic()

Instead of looking at individual words, we will now look at bigram which is a pair of consecutive units such as letters, syllables, or words. The bigram plot now gives us a more detailed and comprehensive description of the topics discussed in each school of thought. For example, we can see German Idealism is about “self consciousness”, “pure reason”, “moral law”, while Phenomenology is about being “objectively present”, “surrounding world”, and “self evidence”. As bigram works really well to describe the text, we can also look at n-gram which is a collection of n successive items in a text document to better understand the context of the text and perform further text analyses.
How has the speech of philosophy evolved over time?
After looking at the text used by philosophers in the major schools of thought, I would like to examine the trend in philosophy speech over time, specifically the sentence length variation and number of distinct words used in the text. I first derived the most original publication date when each school published their text, then ordered the school by their mode publication date. Note that there were no publications happening between the year 170 and the year 1637.
df %>%
ggplot(aes(x = sentence_length, fill = school_ordered)) +
geom_histogram(binwidth = 2, size = 0.25, show.legend = FALSE) +
xlim(0, 500) +
facet_grid(rows = vars(school_ordered)) +
scale_fill_manual(values = palette) +
labs(title = "Sentence Length by School", x = "Word count", y = "Sentence count") +
theme_classic()

Looking at the sentence length distribution by each school, we can see most schools frequently used sentences with ~100-150 words in their texts. However, Plato, Nietszche and Analytic were more likely to use short sentences as their sentence length distributions are either J-shaped or right-skewed, whereas Capitalism and German Idealism were more likely to use longer sentences with >200 words as their sentence length distributions appear more normal or uniform.
df_avg_length <- df %>%
group_by(original_publication_date) %>%
mutate(avg_length_time = round(mean(sentence_length), 0)) %>%
ungroup() %>%
group_by(school_ordered) %>%
mutate(avg_length_school = round(mean(sentence_length), 0)) %>%
ungroup() %>%
distinct(original_publication_date, school_ordered, mode_date, avg_length_time, avg_length_school)
ggplot() +
geom_line(data = df_avg_length, aes(x = original_publication_date, y = avg_length_time), stat = "identity") +
geom_bar(data = distinct(df_avg_length, school_ordered, mode_date, avg_length_school), aes(x = mode_date, y = avg_length_school, fill = school_ordered), stat = "identity", width = 5) +
scale_fill_manual(values = palette) +
labs(title = "Average Sentence Length", x = "Year", y = "Word count", fill = "School") +
theme_classic() +
theme(legend.position = "bottom", legend.direction = "horizontal")

Given the original publication date of the text, I would like to see how the average sentence length has changed over time, corresponding to the school of thought popular at that time. Looking at the overall trend, although it tends to fluctuate towards the later years, its center remain around 100-200 words per sentence. The sentences used by the later schools of thoughts are longer on average, with Capitalism, German Idealism, and Continental having the highest average sentence length, which further confirms our primary observations of sentence length by each school.
df_distinct_word <- df %>%
unnest_tokens(word, sentence_str) %>%
filter(!(word %in% stopwords::stopwords(source = "snowball"))) %>%
group_by(original_publication_date) %>%
mutate(ndistinct_word_time = length(unique(word))) %>%
ungroup() %>%
group_by(school_ordered) %>%
mutate(ndistinct_word_school = length(unique(word))) %>%
ungroup() %>%
distinct(original_publication_date, school_ordered, mode_date, ndistinct_word_time, ndistinct_word_school)
ggplot() +
geom_line(data = df_distinct_word, aes(x = original_publication_date, y = ndistinct_word_time), stat = "identity") +
geom_bar(data = distinct(df_distinct_word, school_ordered, mode_date, ndistinct_word_school), aes(x = mode_date, y = ndistinct_word_school, fill = school_ordered), stat = "identity", width = 5) +
scale_fill_manual(values = palette) +
labs(title = "Number of Distinct Words", x = "Year", y = "Word count", fill = "School") +
theme_classic() +
theme(legend.position = "bottom", legend.direction = "horizontal")

Style of speech is not only reflected through the sentence length, but also through the number of distinct words used. In order to analyze the number of distinct words, I firt tokenized the text, then removed the stop words to extract words that are most important in individual text. The overall number of distinct words aggregated by original publication date tends to decrease over time, from ~20000 to ~10000-12000 distinct words. However, when aggregated by school, the later schools of thought actually seemed more likely to use more distinct words in their text, with German Idealism and Continental having the highest number of distinct words of almost ~30000 words. On the other hand, Stoicism had the lowest number of distinct words, which might link to the fact that it mostly used old English language and therefore its vocabulary might not be as diverse as those of other schools.
What is the sentiment in philosophical text of each school?
Moving on, I would like to conduct a sentiment analysis in order to understand the context of the data and establish a correlation between the given texts. For each extracted sentences, I applied sentiment analysis using NRC sentiment lexicon. Here, we will focus on eight basic emotions (anger, fear, anticipation, trust, surprise, sadness, joy, disgust) and two sentiments (positive and negative).
emotions <- data.table::fread("../output/emotions.csv")
df_emotions <- cbind(df, emotions)
par(mfrow = c(4, 4))
i <- 0
for(s in levels(df$school_ordered)) {
emotions_by_school <- df_emotions %>%
mutate(school = ifelse(school == "german_idealism", "German Idealism", str_to_title(school))) %>%
filter(school == s) %>%
dplyr::select(anger, anticipation, disgust, fear, joy, sadness, surprise, trust) %>%
bind_rows(summarise_all(., ~if(is.numeric(.)) sum(.) else "Total")) %>%
slice_tail(n = 1) %>%
as.data.frame()
emotions_by_school <- rbind(rep(max(emotions_by_school), 8), rep(min(emotions_by_school), 8), emotions_by_school)
i <- i + 1
plt_title <- s
radarchart(emotions_by_school, title = plt_title,
pcol = palette[i], pfcol = alpha(palette[i], 0.3), plwd = 2,
cglcol = "grey", cglty = 1, axislabcol = "grey", caxislabels = seq(0,20,5))
}

Looking at the radar chart of emotions by school, we can see that trust is a dominant emotion in the text of philosophy of all schools of thought, and comes after trust are anticipation and joy. Disgust and surprise tend to be the least popular emotions reflected in most philosophical text. It is interesting to note that Stoicism, Capitalism, Nietzsche and Feminism were the most “joyful” schools, while Communism, Continental and Analytic seemed to be on the more pessimistic end of the spectrum. Specifically, Continental even had significantly higher “fear” compared to other schools, which might be explained by its idea of rejecting the view that the natural sciences are the best or most accurate way of understanding all phenomena.


Putting the sentiments in the context of time, we observe that the sentiment in philosophical text is more likely to be positive and peaks around the 18th century. Of all the emotions, trust remains to be the highest emotion over time. We can also see the pattern that philosophical texts in the olden days seemed to be more neutral, while philosophical texts in the later years seemed to be more emotionally charged as the emotions all have maximum average count during the 18th century.
How similar are the schools of thoughts?
What philosophers have in common is that they all identify problems and look for solutions. Ancient philosophers may have had different, sometimes contradicting theories, but they all actively thought about communal or individual issues and looked for answers. As such, I would like to compare and contrast the different schools of thoughts through both the phisophical text itself and the sentiment reflected in the text written by each school.
corp_sentence <- corpus(df, text_field = "sentence_str")
dfmat_sentence <- corp_sentence %>%
quanteda::tokens(remove_punct = TRUE, remove_symbols = TRUE) %>%
dfm() %>%
dfm_remove(pattern = stopwords("en"))
# dfmat_author <- dfm_group(dfmat_sentence, groups = author)
# tstat_dist <- as.dist(textstat_dist(dfmat_author))
# author_clust <- hclust(tstat_dist)
# plot(author_clust)
dfmat_school <- dfm_group(dfmat_sentence, groups = school_ordered)
tstat_dist <- as.dist(textstat_dist(dfmat_school))
school_clust <- hclust(tstat_dist)
plot(school_clust)

After tokenizing the sentences, I then computed the similarity distance between different schools based on the document-feature matrix which describes how frequently terms occur in the corpus. From the dendogram above, we can detect three major groups of schools:
- Group 1: German Idealism, Aristotle, and Analytic
- Group 2: Plato, Rationalism, Empiricism, Phenomenology, and Continental
- Group 3: Feminism, Stoicism, Nietzsche, Capitalism and Communism
It is interesting how the algorithm returns such groups as I first thought the ancient schools are more similar to one another in terms of styles and ideas in their philosophical text, and similar for the modern schools. Another way to think about it is the origin of the prominent phisophers in each school of thought. In order to better interpret the groups, it is necessary to have some background knowledge in philosophy and understand how philosophers interact with and influence one another over the course of history.
emotions_by_school <- df_emotions %>%
group_by(school_ordered) %>%
summarize(
anger = mean(anger),
anticipation = mean(anticipation),
disgust = mean(disgust),
fear = mean(fear),
joy = mean(joy),
sadness = mean(sadness),
surprise = mean(surprise),
trust = mean(trust)
) %>%
as.data.frame()
rownames(emotions_by_school) <- as.character((emotions_by_school[, 1]))
kmeans_res <- kmeans(emotions_by_school[,-1], iter.max = 200, 5)
fviz_cluster(kmeans_res, stand = FALSE, repel = TRUE,
data = emotions_by_school[,-1], xlab = "", xaxt = "n",
show.clust.cent = FALSE, ggtheme = theme_classic())

To better understand the similarity among different schools, we can also dissect the philosophical texts based on the sentiments. Here, I computed the average count of each emotion by each school, then applied K-Means clustering to find similar groups of schools. We detect five groups of schools that are similar to one another in terms of sentiment:
- Group 1: German Idealism
- Group 2: Plato, Aristotle, Communism, Phenomenology, and Analytic
- Group 3: Feminism
- Group 4: Rationalism, Empiricism, and Capitalism
- Group 5: Stoicism, Nietzsche, and Continental
The groups now seem to be more aligned with my initial hypothesis as schools of the same period of time are grouped together such as Plato and Aristotle, or Rationalism and Empiricism. The reason Stoicism, Nietzsche and Continental are in the same group might be due to their tendency of anticipation and fear, while Feminism might be a standalone group due to its extreme “joy” emotion. Again, one should further study the history of philosophy to better understand these groups and be able to explain why one school is more or less likely to be similar to another school of thought.
What do we learn so far?
- The modern schools of thoughts tend to use more descriptive words, as opposed to the ancient schools which mostly use function words in their texts.
- The average sentence length remains around 100 words, while the number of distinct words decreases over time. The modern schools of thoughts are also more likely to use longer sentences and more distinct words in their texts.
- Trust, anticipation, and joy are the most dominant emotions in philosophical text. Texts written in the 18th century are the most emotionally charged.
- Different schools of thoughts might be more or less similar to one another depending on their period of time, origin, text, or sentiment.
- Study philosophy because it’s interesting!
LS0tCnRpdGxlOiAiUEhJTDEwMSB0aHJvdWdoIHRoZSBMZW5zIG9mIFRleHQgTWluaW5nIgphdXRob3I6ICJLaWV1LUdpYW5nIE5ndXllbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKUGhpbG9zb3BoeSBpcyBhbiBpbXBvcnRhbnQgc3R1ZHkgdGhhdCBwcm92aWRlcyB1cyB3aXRoIHZhbHVhYmxlIHNraWxscyBpbiBsaWZlLiBJdCBwcm9kdWNlcyBiZXR0ZXIgY3JpdGljYWwgdGhpbmtlcnMsIG1vcmUgY3JlYXRpdmUgdGhpbmtlcnMsIGFuZCBiZXR0ZXIgY29tbXVuaWNhdG9ycy4gRGVzcGl0ZSBvbmUncyBrbm93bGVkZ2Ugb2YgcGhpbG9zb3BoeSwgdGhpcyBhbmFseXNpcyBhaW1zIHRvIGdpdmUgYWxsIGxldmVscyBvZiBhdWRpZW5jZSBhIGdlbmVyYWwgcGljdHVyZSBvZiBwaGlsb3NvcGh5IGZyb20gYSBuZXcgcGVyc3BlY3RpdmUsIHVzaW5nIHRleHQgbWluaW5nIGFuZCBkYXRhIHZpc3VhbGl6YXRpb25zIGZyb20gdGhlIFtIaXN0b3J5IG9mIFBoaWxvc29waHldKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMva291cm9zaGFsaXphZGVoL2hpc3Rvcnktb2YtcGhpbG9zb3BoeSkgZGF0YXNldC4gVGhlIGRhdGFzZXQgY29udGFpbnMgb3ZlciAzMDAsMDAwIHNlbnRlbmNlcyBmcm9tIG92ZXIgNTAgdGV4dHMgc3Bhbm5pbmcgMTMgbWFqb3Igc2Nob29scyBvZiBwaGlsb3NvcGh5LiBUaGUgcmVwcmVzZW50ZWQgc2Nob29scyBhcmU6IFBsYXRvLCBBcmlzdG90bGUsIFN0b2ljaXNtLCBSYXRpb25hbGlzbSwgRW1waXJpY2lzbSwgR2VybWFuIElkZWFsaXNtLCBOaWV0enNjaGUsIENvbW11bmlzbSwgQ2FwaXRhbGlzbSwgUGhlbm9tZW5vbG9neSwgQ29udGluZW50YWwsIEFuYWx5dGljLCBhbmQgRmVtaW5pc20uIFNlbnRlbmNlcyBhcmUgdW5pdHMgb2YgYW5hbHlzaXMgZm9yIHRoaXMgcHJvamVjdC4gV2Ugd2lsbCBmaXJzdCB0YWtlIGEgbG9vayBhdCB0aGUgdGV4dCB1c2VkIGluIGVhY2ggc2Nob29sIG9mIHRob3VnaHQsIGV4YW1pbmUgdGhlIHRyZW5kIGluIHBoaWxvc29waGljYWwgc3BlZWNoIG92ZXIgdGltZSwgY29uZHVjdCBhIHNlbnRpbWVudCBhbmFseXNpcywgYW5kIGZpbmFsbHkgY29tcGFyZSB0aGUgc2ltaWxhcml0eSBpbiBwaGlzb3BoaWNhbCB0ZXh0IGFtb25nIGRpZmZlcmVudCBzY2hvb2xzLiBXaXRob3V0IGZ1cnRoZXIgYWRvLCBsZXQncyBkaXZlIGluIQoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoYmVlc3dhcm0pCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShkaWNocm9tYXQpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZmFjdG9leHRyYSkKbGlicmFyeShmbXNiKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KHFkYXApCmxpYnJhcnkocXVhbnRlZGEpCmxpYnJhcnkocXVhbnRlZGEudGV4dHN0YXRzKQpsaWJyYXJ5KFJBTk4pCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHJlYWR0ZXh0KQpsaWJyYXJ5KHJ2ZXN0KQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShzZW50aW1lbnRyKQpsaWJyYXJ5KHN0b3B3b3JkcykKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHN5dXpoZXQpCmxpYnJhcnkodGV4dHJldXNlKQpsaWJyYXJ5KHRpYmJsZSkKbGlicmFyeSh0aWR5dGV4dCkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkodG0pCmxpYnJhcnkodG9waWNtb2RlbHMpCmxpYnJhcnkod2VzYW5kZXJzb24pCmxpYnJhcnkod29yZGNsb3VkKQoKc291cmNlKCIuLi9saWIvcGxvdF9zdGFja2VkLlIiKQpzb3VyY2UoIi4uL2xpYi9zcGVlY2hfZnVuY3MuUiIpCnNvdXJjZSgiLi4vbGliL2hlbHBlcl9mdW5jcy5SIikKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBkZiA8LSByZWFkLmNzdigiLi4vZGF0YS9waGlsb3NvcGh5X2RhdGEuY3N2IikKCiMgUmVhZCBkYXRhIHVzaW5nIGRhdGEudGFibGUgdG8gZGVjcmVhc2UgcnVudGltZQpkZiA8LSBkYXRhLnRhYmxlOjpmcmVhZCgiLi4vb3V0cHV0L3BoaWxvc29waHlfZGF0YV90YWJsZS5jc3YiKQoKZGYgPC0gZGYgJT4lCiAgZ3JvdXBfYnkoc2Nob29sKSAlPiUKICBtdXRhdGUobW9kZV9kYXRlID0gZmluZF9tb2RlKG9yaWdpbmFsX3B1YmxpY2F0aW9uX2RhdGUpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHNjaG9vbCA9IGlmZWxzZShzY2hvb2wgPT0gImdlcm1hbl9pZGVhbGlzbSIsICJHZXJtYW4gSWRlYWxpc20iLCBzdHJfdG9fdGl0bGUoc2Nob29sKSksCiAgICAgICAgIHNjaG9vbF9vcmRlcmVkID0gcmVvcmRlcihmYWN0b3Ioc2Nob29sKSwgbW9kZV9kYXRlLCBtZWFuLCBvcmRlciA9IFRSVUUpKQoKcGFsZXR0ZSA8LSBnZXRfcGFsZXR0ZShsZW5ndGgodW5pcXVlKGRmJHNjaG9vbCkpKQpgYGAKCiMgV2hhdCBpcyB0aGUgbWFpbiBwaGlsb3NvcGh5IGluIGVhY2ggc2Nob29sIG9mIHRob3VnaHQ/CgpGb3IgdGhvc2Ugd2hvIGhhdmUgbmV2ZXIgc3R1ZGllZCBwaGlsb3NvcGh5LCBvciBldmVuIGlmIHlvdSBvbmx5IGtub3cgUGxhdG8gYW5kIEFyaXN0b3RsZSwgeW91IG1pZ2h0IHN0YXJ0IHdvbmRlcmluZyB3aGF0IHRoZSBvdGhlciBtYWpvciBzY2hvb2xzIG9mIHRob3VnaHQgYXJlIGFuZCB3aGF0IHRoZSBtYWluIGlkZWEgb2YgcGhpc29sb3BoeSBpcyBiZWhpbmQgZWFjaCBzY2hvb2wuIFRvIGFuc3dlciB0aG9zZSBxdWVzdGlvbnMsIEkgaGF2ZSBjb25zdHJ1Y3RlZCBhIHNlcmllcyBvZiB3b3JkY2xvdWRzIGFuZCBsb29rZWQgYXQgdGhlIG1vc3QgdXNlZCBiaWdyYW1zIGJ5IGVhY2ggc2Nob29sIGZyb20gdGhlIHBoaWxvc29waHkgdGV4dCBpbiBvdXIgZGF0YS4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpwYXIobWZyb3cgPSBjKDQsIDQpKQoKaSA8LSAwCmZvcihzIGluIGxldmVscyhkZiRzY2hvb2xfb3JkZXJlZCkpIHsKICBkb2NzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UoZGZbZGYkc2Nob29sID09IHMsIF0kc2VudGVuY2Vfc3RyKSkgJT4lCiAgICB0bV9tYXAodG9sb3dlcikgJT4lCiAgICB0bV9tYXAocmVtb3ZlUHVuY3R1YXRpb24pICU+JQogICAgdG1fbWFwKHJlbW92ZU51bWJlcnMpICU+JQogICAgdG1fbWFwKHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoImVuZ2xpc2giKSkgJT4lCiAgICB0bV9tYXAoc3RyaXBXaGl0ZXNwYWNlKQogIAogIHRkbSA8LSBUZXJtRG9jdW1lbnRNYXRyaXgoZG9jcykKICB0ZG1fdGlkeSA8LSB0aWR5KHRkbSkKICB0ZG1fb3ZlcmFsbCA8LSBzdW1tYXJpc2UoZ3JvdXBfYnkodGRtX3RpZHksIHRlcm0pLCBzdW0oY291bnQpKQogIAogIGkgPC0gaSArIDEKICBwbHRfdGl0bGUgPC0gcwogIHdvcmRjbG91ZCh0ZG1fb3ZlcmFsbCR0ZXJtLCB0ZG1fb3ZlcmFsbCRgc3VtKGNvdW50KWAsCiAgICAgICAgICAgIHNjYWxlID0gYyg1LCAwLjUpLAogICAgICAgICAgICBtYXgud29yZHMgPSAyMDAsCiAgICAgICAgICAgIG1pbi5mcmVxID0gMSwKICAgICAgICAgICAgcmFuZG9tLm9yZGVyID0gRkFMU0UsCiAgICAgICAgICAgIHJvdC5wZXIgPSAwLjMsCiAgICAgICAgICAgIHJhbmRvbS5jb2xvciA9IEZBTFNFLAogICAgICAgICAgICBjb2xvcnMgPSBwYWxldHRlW2ldKQogIG10ZXh0KHBsdF90aXRsZSwgc2lkZSA9IDMpCn0KYGBgCgpXb3JkY2xvdWRzIGFyZSB2aXN1YWwgcmVwcmVzZW50YXRpb25zIG9mIHdvcmRzIHRoYXQgZ2l2ZSBncmVhdGVyIHByb21pbmVuY2UgdG8gd29yZHMgdGhhdCBhcHBlYXIgbW9yZSBmcmVxdWVudGx5LiBIZXJlLCBJIGNyZWF0ZWQgYSB3b3JkY2xvdWQgb2YgdGhlIHdvcmRzIG1vc3QgdXNlZCBieSB0aGUgcGhpbG9zb3BoZXJzIGJlbG9uZ2luZyB0byBlYWNoIHNjaG9vbCBvZiB0aG91Z2h0LiBMb29raW5nIGF0IHRoZSB3b3JkY2xvdWRzLCB3ZSBjYW4gc2VlIHRoYXQgdGhlcmUgYXJlIHR3byB0eXBlcyBvZiBzY2hvb2xzOiBvbmUgZnJlcXVlbnRseSB1c2VkIGNvbnRlbnQgd29yZHMgcmVsZXZhbnQgdG8gdGhlaXIgcGhpbG9zb3BoaWVzIGFuZCB0aGUgb3RoZXIgZnJlcXVlbmx5IHVzZWQgZnVuY3Rpb24gd29yZHMgb25seS4gRm9yIGV4YW1wbGUsICoqQ2FwaXRhbGlzbSoqLCAqKkNvbW11bmlzbSoqLCBhbmQgKipGZW1pbmlzbSoqIGFyZSBzY2hvb2xzIHRoYXQgdXNlZCB2ZXJ5IGRlc2NyaXB0aXZlIHdvcmRzIGluIHRoZWlyIHBoaWxvc29waHkgdGV4dHMgYW5kIG9uZSBjb3VsZCBpbmZlciB0aGUgbWFpbiB0aGVtZSBlbXBsb3llZCBieSBlYWNoIHNjaG9vbDogCgoqICoqQ2FwaXRhbGlzbSoqIGZvY3VzZXMgb24gInByaWNlIiwgIm1vbmV5IiwgYW5kICJ2YWx1ZSIgYXMgaXQgZGVzY3JpYmVzIGFuIGVjb25vbWljIGFuZCBwb2xpdGljYWwgc3lzdGVtIGluIHdoaWNoIGEgY291bnRyeSdzIHRyYWRlIGFuZCBpbmR1c3RyeSBhcmUgY29udHJvbGxlZCBieSBwcml2YXRlIG93bmVycyBmb3IgcHJvZml0LCByYXRoZXIgdGhhbiBieSB0aGUgc3RhdGUKKiAqKkNvbW11bmlzbSoqIHBsYWNlcyBlbXBoYXNpcyBvbiAibGFib3VyIiwgInByb2R1Y3Rpb24iLCBhbmQgIndvcmtlcnMiIGFzIGl0IGRlc2NyaWJlcyBhIHNvY2lldHkgaW4gd2hpY2ggYWxsIHByb3BlcnR5IGlzIHB1YmxpY2x5IG93bmVkIGFuZCBlYWNoIHBlcnNvbiB3b3JrcyBhbmQgaXMgcGFpZCBhY2NvcmRpbmcgdG8gdGhlaXIgYWJpbGl0aWVzIGFuZCBuZWVkcwoqICoqRmVtaW5pc20qKiBpcyBjZW50ZXJlZCBhcm91bmQgd29tZW4ncyByaWdodHMgYXMgcmVmbGVjdGVkIGluIHRoZSB1c2Ugb2Ygd29yZHMgc3VjaCBhcyAid29tZW4iLCAiZ2lybCIsICJ3aWZlIiwgYW5kIHBvc3NpYmxseSByYWNpYWwgZGlzY3JpbWluYXRpb24gdGhyb3VnaCB0aGUgdXNlIG9mIHdvcmRzIHN1Y2ggYXMgImJsYWNrIiBhbmQgIndoaXRlIgoKT24gdGhlIG90aGVyIGhhbmQsICoqUGxhdG8qKiwgKipBcmlzdG90bGUqKiwgKipSYXRpb25hbGlzbSoqLCBvciAqKkVtcGlyaWNpc20qKiBhcmUgc2Nob29scyB0aGF0IGRpZG4ndCBzZWVtIHRvIHVzZSBtYW55IGRlc2NyaXB0aXZlIHdvcmRzIHRoYXQgcmVwcmVzZW50IHRoZWlyIHBoaWxvc3BoaWVzIGFzIHdlIG1vc3RseSBzZWUgIm9uZSIsICJ3aWxsIiwgImNhbiIsICJpZGVhcyIgaW4gdGhlaXIgdGV4dHMuIEl0IGNvdWxkIGJlIGV4cGxhaW5lZCBieSB0aGUgZmFjdCB0aGF0IHRoZXNlIGFyZSB0aGUgc2Nob29scyBvZiB0aG91Z2h0cyB0aGF0IGFyZSBvbGRlciBhbmQgdGVuZCB0byBiZSBtb3JlIGFic3RyYWN0LiBTcGVjaWZpY2FsbHksICoqU3RvaWNpc20qKidzIHRleHRzIHdlcmUgaGVhdmlseSB3cml0dGVuIGluIG9sZCBFbmdsaXNoLCB3aGljaCBtYWtlcyBpdCBtb3JlIGRpZmZpY3VsdCB0byB1bmRlcnN0YW5kIGFuZCBpbmZlciB3aGF0IHRoZSBtYWluIHRoZW1lIGlzIGJlaGluZCB0aGVpciBwaGlsb3NwaHkuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9Nn0KZGYgJT4lCiAgdW5uZXN0X3Rva2VucyhiaWdyYW0sIHNlbnRlbmNlX3N0ciwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDIpICU+JQogIHNlcGFyYXRlKGJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiKSwgc2VwID0gIiAiKSAlPiUKICBmaWx0ZXIoIXdvcmQxICVpbiUgc3RvcHdvcmRzOjpzdG9wd29yZHMoc291cmNlID0gInNub3diYWxsIikpICU+JQogIGZpbHRlcighd29yZDIgJWluJSBzdG9wd29yZHM6OnN0b3B3b3Jkcyhzb3VyY2UgPSAic25vd2JhbGwiKSkgJT4lCiAgZmlsdGVyKCFpcy5uYSh3b3JkMSkpICU+JQogIGZpbHRlcighaXMubmEod29yZDIpKSAlPiUKICB1bml0ZShiaWdyYW0sIHdvcmQxLCB3b3JkMiwgc2VwID0gIiAiKSAlPiUKICBncm91cF9ieShzY2hvb2xfb3JkZXJlZCwgYmlncmFtKSAlPiUKICBzdW1tYXJpemUobl9iaWdyYW0gPSBuKCkpICU+JQogIHNsaWNlX21heChuX2JpZ3JhbSwgbiA9IDEwKSAlPiUKICBtdXRhdGUoYmlncmFtID0gcmVvcmRlcl93aXRoaW4oYmlncmFtLCBuX2JpZ3JhbSwgc2Nob29sX29yZGVyZWQpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBiaWdyYW0sIHkgPSBuX2JpZ3JhbSwgZmlsbCA9IHNjaG9vbF9vcmRlcmVkKSkgKwogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgIGZhY2V0X3dyYXAofnNjaG9vbF9vcmRlcmVkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgIGNvb3JkX2ZsaXAoKSArCiAgICBzY2FsZV94X3Jlb3JkZXJlZCgpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGdldF9wYWxldHRlKGxlbmd0aCh1bmlxdWUoZGYkc2Nob29sKSkpKSArCiAgICBsYWJzKHRpdGxlID0gIlRvcCAxMCBCaWdyYW1zIGJ5IFNjaG9vbCIsIHggPSBlbGVtZW50X2JsYW5rKCksIHkgPSAiQ291bnQiKSArCiAgICB0aGVtZV9jbGFzc2ljKCkKYGBgCgpJbnN0ZWFkIG9mIGxvb2tpbmcgYXQgaW5kaXZpZHVhbCB3b3Jkcywgd2Ugd2lsbCBub3cgbG9vayBhdCBiaWdyYW0gd2hpY2ggaXMgYSBwYWlyIG9mIGNvbnNlY3V0aXZlIHVuaXRzIHN1Y2ggYXMgbGV0dGVycywgc3lsbGFibGVzLCBvciB3b3Jkcy4gVGhlIGJpZ3JhbSBwbG90IG5vdyBnaXZlcyB1cyBhIG1vcmUgZGV0YWlsZWQgYW5kIGNvbXByZWhlbnNpdmUgZGVzY3JpcHRpb24gb2YgdGhlIHRvcGljcyBkaXNjdXNzZWQgaW4gZWFjaCBzY2hvb2wgb2YgdGhvdWdodC4gRm9yIGV4YW1wbGUsIHdlIGNhbiBzZWUgKipHZXJtYW4gSWRlYWxpc20qKiBpcyBhYm91dCAic2VsZiBjb25zY2lvdXNuZXNzIiwgInB1cmUgcmVhc29uIiwgIm1vcmFsIGxhdyIsIHdoaWxlICoqUGhlbm9tZW5vbG9neSoqIGlzIGFib3V0IGJlaW5nICJvYmplY3RpdmVseSBwcmVzZW50IiwgInN1cnJvdW5kaW5nIHdvcmxkIiwgYW5kICJzZWxmIGV2aWRlbmNlIi4gQXMgYmlncmFtIHdvcmtzIHJlYWxseSB3ZWxsIHRvIGRlc2NyaWJlIHRoZSB0ZXh0LCB3ZSBjYW4gYWxzbyBsb29rIGF0IG4tZ3JhbSB3aGljaCBpcyBhIGNvbGxlY3Rpb24gb2YgKm4qIHN1Y2Nlc3NpdmUgaXRlbXMgaW4gYSB0ZXh0IGRvY3VtZW50IHRvIGJldHRlciB1bmRlcnN0YW5kIHRoZSBjb250ZXh0IG9mIHRoZSB0ZXh0IGFuZCBwZXJmb3JtIGZ1cnRoZXIgdGV4dCBhbmFseXNlcy4KCiMgSG93IGhhcyB0aGUgc3BlZWNoIG9mIHBoaWxvc29waHkgZXZvbHZlZCBvdmVyIHRpbWU/CgpBZnRlciBsb29raW5nIGF0IHRoZSB0ZXh0IHVzZWQgYnkgcGhpbG9zb3BoZXJzIGluIHRoZSBtYWpvciBzY2hvb2xzIG9mIHRob3VnaHQsIEkgd291bGQgbGlrZSB0byBleGFtaW5lIHRoZSB0cmVuZCBpbiBwaGlsb3NvcGh5IHNwZWVjaCBvdmVyIHRpbWUsIHNwZWNpZmljYWxseSB0aGUgc2VudGVuY2UgbGVuZ3RoIHZhcmlhdGlvbiBhbmQgbnVtYmVyIG9mIGRpc3RpbmN0IHdvcmRzIHVzZWQgaW4gdGhlIHRleHQuIEkgZmlyc3QgZGVyaXZlZCB0aGUgbW9zdCBvcmlnaW5hbCBwdWJsaWNhdGlvbiBkYXRlIHdoZW4gZWFjaCBzY2hvb2wgcHVibGlzaGVkIHRoZWlyIHRleHQsIHRoZW4gb3JkZXJlZCB0aGUgc2Nob29sIGJ5IHRoZWlyIG1vZGUgcHVibGljYXRpb24gZGF0ZS4gTm90ZSB0aGF0IHRoZXJlIHdlcmUgbm8gcHVibGljYXRpb25zIGhhcHBlbmluZyBiZXR3ZWVuIHRoZSB5ZWFyIDE3MCBhbmQgdGhlIHllYXIgMTYzNy4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpkZiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzZW50ZW5jZV9sZW5ndGgsIGZpbGwgPSBzY2hvb2xfb3JkZXJlZCkpICsKICAgIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMiwgc2l6ZSA9IDAuMjUsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgIHhsaW0oMCwgNTAwKSArCiAgICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKHNjaG9vbF9vcmRlcmVkKSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcGFsZXR0ZSkgKwogICAgbGFicyh0aXRsZSA9ICJTZW50ZW5jZSBMZW5ndGggYnkgU2Nob29sIiwgeCA9ICJXb3JkIGNvdW50IiwgeSA9ICJTZW50ZW5jZSBjb3VudCIpICsKICAgIHRoZW1lX2NsYXNzaWMoKQpgYGAKCkxvb2tpbmcgYXQgdGhlIHNlbnRlbmNlIGxlbmd0aCBkaXN0cmlidXRpb24gYnkgZWFjaCBzY2hvb2wsIHdlIGNhbiBzZWUgbW9zdCBzY2hvb2xzIGZyZXF1ZW50bHkgdXNlZCBzZW50ZW5jZXMgd2l0aCB+MTAwLTE1MCB3b3JkcyBpbiB0aGVpciB0ZXh0cy4gSG93ZXZlciwgKipQbGF0byoqLCAqKk5pZXRzemNoZSoqIGFuZCAqKkFuYWx5dGljKiogd2VyZSBtb3JlIGxpa2VseSB0byB1c2Ugc2hvcnQgc2VudGVuY2VzIGFzIHRoZWlyIHNlbnRlbmNlIGxlbmd0aCBkaXN0cmlidXRpb25zIGFyZSBlaXRoZXIgSi1zaGFwZWQgb3IgcmlnaHQtc2tld2VkLCB3aGVyZWFzICoqQ2FwaXRhbGlzbSoqIGFuZCAqKkdlcm1hbiBJZGVhbGlzbSoqIHdlcmUgbW9yZSBsaWtlbHkgdG8gdXNlIGxvbmdlciBzZW50ZW5jZXMgd2l0aCA+MjAwIHdvcmRzIGFzIHRoZWlyIHNlbnRlbmNlIGxlbmd0aCBkaXN0cmlidXRpb25zIGFwcGVhciBtb3JlIG5vcm1hbCBvciB1bmlmb3JtLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTN9CmRmX2F2Z19sZW5ndGggPC0gZGYgJT4lCiAgZ3JvdXBfYnkob3JpZ2luYWxfcHVibGljYXRpb25fZGF0ZSkgJT4lCiAgbXV0YXRlKGF2Z19sZW5ndGhfdGltZSA9IHJvdW5kKG1lYW4oc2VudGVuY2VfbGVuZ3RoKSwgMCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBncm91cF9ieShzY2hvb2xfb3JkZXJlZCkgJT4lCiAgbXV0YXRlKGF2Z19sZW5ndGhfc2Nob29sID0gcm91bmQobWVhbihzZW50ZW5jZV9sZW5ndGgpLCAwKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGRpc3RpbmN0KG9yaWdpbmFsX3B1YmxpY2F0aW9uX2RhdGUsIHNjaG9vbF9vcmRlcmVkLCBtb2RlX2RhdGUsIGF2Z19sZW5ndGhfdGltZSwgYXZnX2xlbmd0aF9zY2hvb2wpCgpnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkZl9hdmdfbGVuZ3RoLCBhZXMoeCA9IG9yaWdpbmFsX3B1YmxpY2F0aW9uX2RhdGUsIHkgPSBhdmdfbGVuZ3RoX3RpbWUpLCBzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fYmFyKGRhdGEgPSBkaXN0aW5jdChkZl9hdmdfbGVuZ3RoLCBzY2hvb2xfb3JkZXJlZCwgbW9kZV9kYXRlLCBhdmdfbGVuZ3RoX3NjaG9vbCksIGFlcyh4ID0gbW9kZV9kYXRlLCB5ID0gYXZnX2xlbmd0aF9zY2hvb2wsIGZpbGwgPSBzY2hvb2xfb3JkZXJlZCksIHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDUpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlKSArCiAgbGFicyh0aXRsZSA9ICJBdmVyYWdlIFNlbnRlbmNlIExlbmd0aCIsIHggPSAiWWVhciIsIHkgPSAiV29yZCBjb3VudCIsIGZpbGwgPSAiU2Nob29sIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpCmBgYAoKR2l2ZW4gdGhlIG9yaWdpbmFsIHB1YmxpY2F0aW9uIGRhdGUgb2YgdGhlIHRleHQsIEkgd291bGQgbGlrZSB0byBzZWUgaG93IHRoZSBhdmVyYWdlIHNlbnRlbmNlIGxlbmd0aCBoYXMgY2hhbmdlZCBvdmVyIHRpbWUsIGNvcnJlc3BvbmRpbmcgdG8gdGhlIHNjaG9vbCBvZiB0aG91Z2h0IHBvcHVsYXIgYXQgdGhhdCB0aW1lLiBMb29raW5nIGF0IHRoZSBvdmVyYWxsIHRyZW5kLCBhbHRob3VnaCBpdCB0ZW5kcyB0byBmbHVjdHVhdGUgdG93YXJkcyB0aGUgbGF0ZXIgeWVhcnMsIGl0cyBjZW50ZXIgcmVtYWluIGFyb3VuZCAxMDAtMjAwIHdvcmRzIHBlciBzZW50ZW5jZS4gVGhlIHNlbnRlbmNlcyB1c2VkIGJ5IHRoZSBsYXRlciBzY2hvb2xzIG9mIHRob3VnaHRzIGFyZSBsb25nZXIgb24gYXZlcmFnZSwgd2l0aCAqKkNhcGl0YWxpc20qKiwgKipHZXJtYW4gSWRlYWxpc20qKiwgYW5kICoqQ29udGluZW50YWwqKiBoYXZpbmcgdGhlIGhpZ2hlc3QgYXZlcmFnZSBzZW50ZW5jZSBsZW5ndGgsIHdoaWNoIGZ1cnRoZXIgY29uZmlybXMgb3VyIHByaW1hcnkgb2JzZXJ2YXRpb25zIG9mIHNlbnRlbmNlIGxlbmd0aCBieSBlYWNoIHNjaG9vbC4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0zfQpkZl9kaXN0aW5jdF93b3JkIDwtIGRmICU+JQogIHVubmVzdF90b2tlbnMod29yZCwgc2VudGVuY2Vfc3RyKSAlPiUKICBmaWx0ZXIoISh3b3JkICVpbiUgc3RvcHdvcmRzOjpzdG9wd29yZHMoc291cmNlID0gInNub3diYWxsIikpKSAlPiUKICBncm91cF9ieShvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlKSAlPiUKICBtdXRhdGUobmRpc3RpbmN0X3dvcmRfdGltZSA9IGxlbmd0aCh1bmlxdWUod29yZCkpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ3JvdXBfYnkoc2Nob29sX29yZGVyZWQpICU+JQogIG11dGF0ZShuZGlzdGluY3Rfd29yZF9zY2hvb2wgPSBsZW5ndGgodW5pcXVlKHdvcmQpKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGRpc3RpbmN0KG9yaWdpbmFsX3B1YmxpY2F0aW9uX2RhdGUsIHNjaG9vbF9vcmRlcmVkLCBtb2RlX2RhdGUsIG5kaXN0aW5jdF93b3JkX3RpbWUsIG5kaXN0aW5jdF93b3JkX3NjaG9vbCkKCmdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGRmX2Rpc3RpbmN0X3dvcmQsIGFlcyh4ID0gb3JpZ2luYWxfcHVibGljYXRpb25fZGF0ZSwgeSA9IG5kaXN0aW5jdF93b3JkX3RpbWUpLCBzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fYmFyKGRhdGEgPSBkaXN0aW5jdChkZl9kaXN0aW5jdF93b3JkLCBzY2hvb2xfb3JkZXJlZCwgbW9kZV9kYXRlLCBuZGlzdGluY3Rfd29yZF9zY2hvb2wpLCBhZXMoeCA9IG1vZGVfZGF0ZSwgeSA9IG5kaXN0aW5jdF93b3JkX3NjaG9vbCwgZmlsbCA9IHNjaG9vbF9vcmRlcmVkKSwgc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gNSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUpICsKICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBEaXN0aW5jdCBXb3JkcyIsIHggPSAiWWVhciIsIHkgPSAiV29yZCBjb3VudCIsIGZpbGwgPSAiU2Nob29sIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpCmBgYAoKU3R5bGUgb2Ygc3BlZWNoIGlzIG5vdCBvbmx5IHJlZmxlY3RlZCB0aHJvdWdoIHRoZSBzZW50ZW5jZSBsZW5ndGgsIGJ1dCBhbHNvIHRocm91Z2ggdGhlIG51bWJlciBvZiBkaXN0aW5jdCB3b3JkcyB1c2VkLiBJbiBvcmRlciB0byBhbmFseXplIHRoZSBudW1iZXIgb2YgZGlzdGluY3Qgd29yZHMsIEkgZmlydCB0b2tlbml6ZWQgdGhlIHRleHQsIHRoZW4gcmVtb3ZlZCB0aGUgc3RvcCB3b3JkcyB0byBleHRyYWN0IHdvcmRzIHRoYXQgYXJlIG1vc3QgaW1wb3J0YW50IGluIGluZGl2aWR1YWwgdGV4dC4gVGhlIG92ZXJhbGwgbnVtYmVyIG9mIGRpc3RpbmN0IHdvcmRzIGFnZ3JlZ2F0ZWQgYnkgb3JpZ2luYWwgcHVibGljYXRpb24gZGF0ZSB0ZW5kcyB0byBkZWNyZWFzZSBvdmVyIHRpbWUsIGZyb20gfjIwMDAwIHRvIH4xMDAwMC0xMjAwMCBkaXN0aW5jdCB3b3Jkcy4gSG93ZXZlciwgd2hlbiBhZ2dyZWdhdGVkIGJ5IHNjaG9vbCwgdGhlIGxhdGVyIHNjaG9vbHMgb2YgdGhvdWdodCBhY3R1YWxseSBzZWVtZWQgbW9yZSBsaWtlbHkgdG8gdXNlIG1vcmUgZGlzdGluY3Qgd29yZHMgaW4gdGhlaXIgdGV4dCwgd2l0aCAqKkdlcm1hbiBJZGVhbGlzbSoqIGFuZCAqKkNvbnRpbmVudGFsKiogaGF2aW5nIHRoZSBoaWdoZXN0IG51bWJlciBvZiBkaXN0aW5jdCB3b3JkcyBvZiBhbG1vc3QgfjMwMDAwIHdvcmRzLiBPbiB0aGUgb3RoZXIgaGFuZCwgU3RvaWNpc20gaGFkIHRoZSBsb3dlc3QgbnVtYmVyIG9mIGRpc3RpbmN0IHdvcmRzLCB3aGljaCBtaWdodCBsaW5rIHRvIHRoZSBmYWN0IHRoYXQgaXQgbW9zdGx5IHVzZWQgb2xkIEVuZ2xpc2ggbGFuZ3VhZ2UgYW5kIHRoZXJlZm9yZSBpdHMgdm9jYWJ1bGFyeSBtaWdodCBub3QgYmUgYXMgZGl2ZXJzZSBhcyB0aG9zZSBvZiBvdGhlciBzY2hvb2xzLgoKIyBXaGF0IGlzIHRoZSBzZW50aW1lbnQgaW4gcGhpbG9zb3BoaWNhbCB0ZXh0IG9mIGVhY2ggc2Nob29sPwoKTW92aW5nIG9uLCBJIHdvdWxkIGxpa2UgdG8gY29uZHVjdCBhIHNlbnRpbWVudCBhbmFseXNpcyBpbiBvcmRlciB0byB1bmRlcnN0YW5kIHRoZSBjb250ZXh0IG9mIHRoZSBkYXRhIGFuZCBlc3RhYmxpc2ggYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBnaXZlbiB0ZXh0cy4gRm9yIGVhY2ggZXh0cmFjdGVkIHNlbnRlbmNlcywgSSBhcHBsaWVkIHNlbnRpbWVudCBhbmFseXNpcyB1c2luZyBbTlJDIHNlbnRpbWVudCBsZXhpY29uXShodHRwOi8vc2FpZm1vaGFtbWFkLmNvbS9XZWJQYWdlcy9OUkMtRW1vdGlvbi1MZXhpY29uLmh0bSkuIEhlcmUsIHdlIHdpbGwgZm9jdXMgb24gZWlnaHQgYmFzaWMgZW1vdGlvbnMgKGFuZ2VyLCBmZWFyLCBhbnRpY2lwYXRpb24sIHRydXN0LCBzdXJwcmlzZSwgc2FkbmVzcywgam95LCBkaXNndXN0KSBhbmQgdHdvIHNlbnRpbWVudHMgKHBvc2l0aXZlIGFuZCBuZWdhdGl2ZSkuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZW1vdGlvbnMgPC0gZGF0YS50YWJsZTo6ZnJlYWQoIi4uL291dHB1dC9lbW90aW9ucy5jc3YiKQpkZl9lbW90aW9ucyA8LSBjYmluZChkZiwgZW1vdGlvbnMpCmBgYAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CnBhcihtZnJvdyA9IGMoNCwgNCkpCgppIDwtIDAKZm9yKHMgaW4gbGV2ZWxzKGRmJHNjaG9vbF9vcmRlcmVkKSkgewogIGVtb3Rpb25zX2J5X3NjaG9vbCA8LSBkZl9lbW90aW9ucyAlPiUKICAgIG11dGF0ZShzY2hvb2wgPSBpZmVsc2Uoc2Nob29sID09ICJnZXJtYW5faWRlYWxpc20iLCAiR2VybWFuIElkZWFsaXNtIiwgc3RyX3RvX3RpdGxlKHNjaG9vbCkpKSAlPiUKICAgIGZpbHRlcihzY2hvb2wgPT0gcykgJT4lCiAgICBkcGx5cjo6c2VsZWN0KGFuZ2VyLCBhbnRpY2lwYXRpb24sIGRpc2d1c3QsIGZlYXIsIGpveSwgc2FkbmVzcywgc3VycHJpc2UsIHRydXN0KSAlPiUKICAgIGJpbmRfcm93cyhzdW1tYXJpc2VfYWxsKC4sIH5pZihpcy5udW1lcmljKC4pKSBzdW0oLikgZWxzZSAiVG90YWwiKSkgJT4lCiAgICBzbGljZV90YWlsKG4gPSAxKSAlPiUKICAgIGFzLmRhdGEuZnJhbWUoKQoKICBlbW90aW9uc19ieV9zY2hvb2wgPC0gcmJpbmQocmVwKG1heChlbW90aW9uc19ieV9zY2hvb2wpLCA4KSwgcmVwKG1pbihlbW90aW9uc19ieV9zY2hvb2wpLCA4KSwgZW1vdGlvbnNfYnlfc2Nob29sKQogIAogIGkgPC0gaSArIDEKICBwbHRfdGl0bGUgPC0gcwogIHJhZGFyY2hhcnQoZW1vdGlvbnNfYnlfc2Nob29sLCB0aXRsZSA9IHBsdF90aXRsZSwKICAgICAgICAgICBwY29sID0gcGFsZXR0ZVtpXSwgcGZjb2wgPSBhbHBoYShwYWxldHRlW2ldLCAwLjMpLCBwbHdkID0gMiwKICAgICAgICAgICBjZ2xjb2wgPSAiZ3JleSIsIGNnbHR5ID0gMSwgYXhpc2xhYmNvbCA9ICJncmV5IiwgY2F4aXNsYWJlbHMgPSBzZXEoMCwyMCw1KSkKfQpgYGAKCkxvb2tpbmcgYXQgdGhlIHJhZGFyIGNoYXJ0IG9mIGVtb3Rpb25zIGJ5IHNjaG9vbCwgd2UgY2FuIHNlZSB0aGF0IHRydXN0IGlzIGEgZG9taW5hbnQgZW1vdGlvbiBpbiB0aGUgdGV4dCBvZiBwaGlsb3NvcGh5IG9mIGFsbCBzY2hvb2xzIG9mIHRob3VnaHQsIGFuZCBjb21lcyBhZnRlciB0cnVzdCBhcmUgYW50aWNpcGF0aW9uIGFuZCBqb3kuIERpc2d1c3QgYW5kIHN1cnByaXNlIHRlbmQgdG8gYmUgdGhlIGxlYXN0IHBvcHVsYXIgZW1vdGlvbnMgcmVmbGVjdGVkIGluIG1vc3QgcGhpbG9zb3BoaWNhbCB0ZXh0LiBJdCBpcyBpbnRlcmVzdGluZyB0byBub3RlIHRoYXQgKipTdG9pY2lzbSoqLCAqKkNhcGl0YWxpc20qKiwgKipOaWV0enNjaGUqKiBhbmQgKipGZW1pbmlzbSoqIHdlcmUgdGhlIG1vc3QgImpveWZ1bCIgc2Nob29scywgd2hpbGUgKipDb21tdW5pc20qKiwgKipDb250aW5lbnRhbCoqIGFuZCAqKkFuYWx5dGljKiogc2VlbWVkIHRvIGJlIG9uIHRoZSBtb3JlIHBlc3NpbWlzdGljIGVuZCBvZiB0aGUgc3BlY3RydW0uIFNwZWNpZmljYWxseSwgKipDb250aW5lbnRhbCoqIGV2ZW4gaGFkIHNpZ25pZmljYW50bHkgaGlnaGVyICJmZWFyIiBjb21wYXJlZCB0byBvdGhlciBzY2hvb2xzLCB3aGljaCBtaWdodCBiZSBleHBsYWluZWQgYnkgaXRzIGlkZWEgb2YgcmVqZWN0aW5nIHRoZSB2aWV3IHRoYXQgdGhlIG5hdHVyYWwgc2NpZW5jZXMgYXJlIHRoZSBiZXN0IG9yIG1vc3QgYWNjdXJhdGUgd2F5IG9mIHVuZGVyc3RhbmRpbmcgYWxsIHBoZW5vbWVuYS4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0zfQojIERlZmF1bHQgY29sb3JzOiAiI0Y4NzY2RCIsICIjMDBCRkM0IgpkZl9lbW90aW9ucyAlPiUKICBncm91cF9ieShvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlKSAlPiUKICBzdW1tYXJpemUocG9zaXRpdmUgPSBtZWFuKHBvc2l0aXZlKSwKICAgICAgICAgICAgbmVnYXRpdmUgPSBtZWFuKG5lZ2F0aXZlKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKCFvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlLCBuYW1lc190byA9ICJlbW90aW9uIiwgdmFsdWVzX3RvID0gImF2Z19jb3VudCIpICU+JQogIGdncGxvdChhZXMoeCA9IG9yaWdpbmFsX3B1YmxpY2F0aW9uX2RhdGUsIHkgPSBhdmdfY291bnQsIGNvbG9yID0gZW1vdGlvbikpICsKICAgIGdlb21fbGluZShzdGF0ID0gImlkZW50aXR5IikgKwogICAgbGFicyh0aXRsZSA9ICJTZW50aW1lbnQgb3ZlciBUaW1lIiwgeCA9ICJZZWFyIiwgeSA9ICJBdmVyYWdlIGNvdW50IiwgY29sb3IgPSAiRW1vdGlvbiIpICsKICAgIHRoZW1lX2NsYXNzaWMoKQpgYGAKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0zfQpkZl9lbW90aW9ucyAlPiUKICBncm91cF9ieShvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlKSAlPiUKICBzdW1tYXJpemUoYW5nZXIgPSBtZWFuKGFuZ2VyKSwKICAgICAgICAgICAgYW50aWNpcGF0aW9uID0gbWVhbihhbnRpY2lwYXRpb24pLAogICAgICAgICAgICBkaXNndXN0ID0gbWVhbihkaXNndXN0KSwKICAgICAgICAgICAgZmVhciA9IG1lYW4oZmVhciksCiAgICAgICAgICAgIGpveSA9IG1lYW4oam95KSwKICAgICAgICAgICAgc2FkbmVzcyA9IG1lYW4oc2FkbmVzcyksCiAgICAgICAgICAgIHN1cnByaXNlID0gbWVhbihzdXJwcmlzZSksCiAgICAgICAgICAgIHRydXN0ID0gbWVhbih0cnVzdCkpICU+JQogIHBpdm90X2xvbmdlcighb3JpZ2luYWxfcHVibGljYXRpb25fZGF0ZSwgbmFtZXNfdG8gPSAiZW1vdGlvbiIsIHZhbHVlc190byA9ICJhdmdfY291bnQiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlLCB5ID0gYXZnX2NvdW50LCBjb2xvciA9IGVtb3Rpb24pKSArCiAgICBnZW9tX2xpbmUoc3RhdCA9ICJpZGVudGl0eSIpICsKICAgIGxhYnModGl0bGUgPSAiRW1vdGlvbiBvdmVyIFRpbWUiLCB4ID0gIlllYXIiLCB5ID0gIkF2ZXJhZ2UgY291bnQiLCBjb2xvciA9ICJFbW90aW9uIikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJSdXNobW9yZTEiLCA4LCB0eXBlID0gImNvbnRpbnVvdXMiKSkgKwogICAgdGhlbWVfY2xhc3NpYygpCmBgYAoKUHV0dGluZyB0aGUgc2VudGltZW50cyBpbiB0aGUgY29udGV4dCBvZiB0aW1lLCB3ZSBvYnNlcnZlIHRoYXQgdGhlIHNlbnRpbWVudCBpbiBwaGlsb3NvcGhpY2FsIHRleHQgaXMgbW9yZSBsaWtlbHkgdG8gYmUgcG9zaXRpdmUgYW5kIHBlYWtzIGFyb3VuZCB0aGUgMTh0aCBjZW50dXJ5LiBPZiBhbGwgdGhlIGVtb3Rpb25zLCB0cnVzdCByZW1haW5zIHRvIGJlIHRoZSBoaWdoZXN0IGVtb3Rpb24gb3ZlciB0aW1lLiBXZSBjYW4gYWxzbyBzZWUgdGhlIHBhdHRlcm4gdGhhdCBwaGlsb3NvcGhpY2FsIHRleHRzIGluIHRoZSBvbGRlbiBkYXlzIHNlZW1lZCB0byBiZSBtb3JlIG5ldXRyYWwsIHdoaWxlIHBoaWxvc29waGljYWwgdGV4dHMgaW4gdGhlIGxhdGVyIHllYXJzIHNlZW1lZCB0byBiZSBtb3JlIGVtb3Rpb25hbGx5IGNoYXJnZWQgYXMgdGhlIGVtb3Rpb25zIGFsbCBoYXZlIG1heGltdW0gYXZlcmFnZSBjb3VudCBkdXJpbmcgdGhlIDE4dGggY2VudHVyeS4KCiMgSG93IHNpbWlsYXIgYXJlIHRoZSBzY2hvb2xzIG9mIHRob3VnaHRzPwoKV2hhdCBwaGlsb3NvcGhlcnMgaGF2ZSBpbiBjb21tb24gaXMgdGhhdCB0aGV5IGFsbCBpZGVudGlmeSBwcm9ibGVtcyBhbmQgbG9vayBmb3Igc29sdXRpb25zLiBBbmNpZW50IHBoaWxvc29waGVycyBtYXkgaGF2ZSBoYWQgZGlmZmVyZW50LCBzb21ldGltZXMgY29udHJhZGljdGluZyB0aGVvcmllcywgYnV0IHRoZXkgYWxsIGFjdGl2ZWx5IHRob3VnaHQgYWJvdXQgY29tbXVuYWwgb3IgaW5kaXZpZHVhbCBpc3N1ZXMgYW5kIGxvb2tlZCBmb3IgYW5zd2Vycy4gQXMgc3VjaCwgSSB3b3VsZCBsaWtlIHRvIGNvbXBhcmUgYW5kIGNvbnRyYXN0IHRoZSBkaWZmZXJlbnQgc2Nob29scyBvZiB0aG91Z2h0cyB0aHJvdWdoIGJvdGggdGhlIHBoaXNvcGhpY2FsIHRleHQgaXRzZWxmIGFuZCB0aGUgc2VudGltZW50IHJlZmxlY3RlZCBpbiB0aGUgdGV4dCB3cml0dGVuIGJ5IGVhY2ggc2Nob29sLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTN9CmNvcnBfc2VudGVuY2UgPC0gY29ycHVzKGRmLCB0ZXh0X2ZpZWxkID0gInNlbnRlbmNlX3N0ciIpCgpkZm1hdF9zZW50ZW5jZSA8LSBjb3JwX3NlbnRlbmNlICU+JQogIHF1YW50ZWRhOjp0b2tlbnMocmVtb3ZlX3B1bmN0ID0gVFJVRSwgcmVtb3ZlX3N5bWJvbHMgPSBUUlVFKSAlPiUgCiAgZGZtKCkgJT4lCiAgZGZtX3JlbW92ZShwYXR0ZXJuID0gc3RvcHdvcmRzKCJlbiIpKQoKZGZtYXRfc2Nob29sIDwtIGRmbV9ncm91cChkZm1hdF9zZW50ZW5jZSwgZ3JvdXBzID0gc2Nob29sX29yZGVyZWQpCnRzdGF0X2Rpc3QgPC0gYXMuZGlzdCh0ZXh0c3RhdF9kaXN0KGRmbWF0X3NjaG9vbCkpCnNjaG9vbF9jbHVzdCA8LSBoY2x1c3QodHN0YXRfZGlzdCkKcGxvdChzY2hvb2xfY2x1c3QpCmBgYAoKQWZ0ZXIgdG9rZW5pemluZyB0aGUgc2VudGVuY2VzLCBJIHRoZW4gY29tcHV0ZWQgdGhlIHNpbWlsYXJpdHkgZGlzdGFuY2UgYmV0d2VlbiBkaWZmZXJlbnQgc2Nob29scyBiYXNlZCBvbiB0aGUgZG9jdW1lbnQtZmVhdHVyZSBtYXRyaXggd2hpY2ggZGVzY3JpYmVzIGhvdyBmcmVxdWVudGx5IHRlcm1zIG9jY3VyIGluIHRoZSBjb3JwdXMuIEZyb20gdGhlIGRlbmRvZ3JhbSBhYm92ZSwgd2UgY2FuIGRldGVjdCB0aHJlZSBtYWpvciBncm91cHMgb2Ygc2Nob29sczoKCiogR3JvdXAgMTogKipHZXJtYW4gSWRlYWxpc20qKiwgKipBcmlzdG90bGUqKiwgYW5kICoqQW5hbHl0aWMqKgoqIEdyb3VwIDI6ICoqUGxhdG8qKiwgKipSYXRpb25hbGlzbSoqLCAqKkVtcGlyaWNpc20qKiwgKipQaGVub21lbm9sb2d5KiosIGFuZCAqKkNvbnRpbmVudGFsKioKKiBHcm91cCAzOiAqKkZlbWluaXNtKiosICoqU3RvaWNpc20qKiwgKipOaWV0enNjaGUqKiwgKipDYXBpdGFsaXNtKiogYW5kICoqQ29tbXVuaXNtKioKCkl0IGlzIGludGVyZXN0aW5nIGhvdyB0aGUgYWxnb3JpdGhtIHJldHVybnMgc3VjaCBncm91cHMgYXMgSSBmaXJzdCB0aG91Z2h0IHRoZSBhbmNpZW50IHNjaG9vbHMgYXJlIG1vcmUgc2ltaWxhciB0byBvbmUgYW5vdGhlciBpbiB0ZXJtcyBvZiBzdHlsZXMgYW5kIGlkZWFzIGluIHRoZWlyIHBoaWxvc29waGljYWwgdGV4dCwgYW5kIHNpbWlsYXIgZm9yIHRoZSBtb2Rlcm4gc2Nob29scy4gQW5vdGhlciB3YXkgdG8gdGhpbmsgYWJvdXQgaXQgaXMgdGhlIG9yaWdpbiBvZiB0aGUgcHJvbWluZW50IHBoaXNvcGhlcnMgaW4gZWFjaCBzY2hvb2wgb2YgdGhvdWdodC4gSW4gb3JkZXIgdG8gYmV0dGVyIGludGVycHJldCB0aGUgZ3JvdXBzLCBpdCBpcyBuZWNlc3NhcnkgdG8gaGF2ZSBzb21lIGJhY2tncm91bmQga25vd2xlZGdlIGluIHBoaWxvc29waHkgYW5kIHVuZGVyc3RhbmQgaG93IHBoaWxvc29waGVycyBpbnRlcmFjdCB3aXRoIGFuZCBpbmZsdWVuY2Ugb25lIGFub3RoZXIgb3ZlciB0aGUgY291cnNlIG9mIGhpc3RvcnkuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9M30KZW1vdGlvbnNfYnlfc2Nob29sIDwtIGRmX2Vtb3Rpb25zICU+JQogIGdyb3VwX2J5KHNjaG9vbF9vcmRlcmVkKSAlPiUKICBzdW1tYXJpemUoCiAgICBhbmdlciA9IG1lYW4oYW5nZXIpLAogICAgYW50aWNpcGF0aW9uID0gbWVhbihhbnRpY2lwYXRpb24pLAogICAgZGlzZ3VzdCA9IG1lYW4oZGlzZ3VzdCksCiAgICBmZWFyID0gbWVhbihmZWFyKSwKICAgIGpveSA9IG1lYW4oam95KSwKICAgIHNhZG5lc3MgPSBtZWFuKHNhZG5lc3MpLAogICAgc3VycHJpc2UgPSBtZWFuKHN1cnByaXNlKSwKICAgIHRydXN0ID0gbWVhbih0cnVzdCkKICApICU+JQogIGFzLmRhdGEuZnJhbWUoKQoKcm93bmFtZXMoZW1vdGlvbnNfYnlfc2Nob29sKSA8LSBhcy5jaGFyYWN0ZXIoKGVtb3Rpb25zX2J5X3NjaG9vbFssIDFdKSkKa21lYW5zX3JlcyA8LSBrbWVhbnMoZW1vdGlvbnNfYnlfc2Nob29sWywtMV0sIGl0ZXIubWF4ID0gMjAwLCA1KQpmdml6X2NsdXN0ZXIoa21lYW5zX3Jlcywgc3RhbmQgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLAogICAgICAgICAgICAgZGF0YSA9IGVtb3Rpb25zX2J5X3NjaG9vbFssLTFdLCB4bGFiID0gIiIsIHhheHQgPSAibiIsCiAgICAgICAgICAgICBzaG93LmNsdXN0LmNlbnQgPSBGQUxTRSwgZ2d0aGVtZSA9IHRoZW1lX2NsYXNzaWMoKSkKYGBgCgpUbyBiZXR0ZXIgdW5kZXJzdGFuZCB0aGUgc2ltaWxhcml0eSBhbW9uZyBkaWZmZXJlbnQgc2Nob29scywgd2UgY2FuIGFsc28gZGlzc2VjdCB0aGUgcGhpbG9zb3BoaWNhbCB0ZXh0cyBiYXNlZCBvbiB0aGUgc2VudGltZW50cy4gSGVyZSwgSSBjb21wdXRlZCB0aGUgYXZlcmFnZSBjb3VudCBvZiBlYWNoIGVtb3Rpb24gYnkgZWFjaCBzY2hvb2wsIHRoZW4gYXBwbGllZCBLLU1lYW5zIGNsdXN0ZXJpbmcgdG8gZmluZCBzaW1pbGFyIGdyb3VwcyBvZiBzY2hvb2xzLiBXZSBkZXRlY3QgZml2ZSBncm91cHMgb2Ygc2Nob29scyB0aGF0IGFyZSBzaW1pbGFyIHRvIG9uZSBhbm90aGVyIGluIHRlcm1zIG9mIHNlbnRpbWVudDogCgoqIEdyb3VwIDE6ICoqR2VybWFuIElkZWFsaXNtKioKKiBHcm91cCAyOiAqKlBsYXRvKiosICoqQXJpc3RvdGxlKiosICoqQ29tbXVuaXNtKiosICoqUGhlbm9tZW5vbG9neSoqLCBhbmQgKipBbmFseXRpYyoqCiogR3JvdXAgMzogKipGZW1pbmlzbSoqCiogR3JvdXAgNDogKipSYXRpb25hbGlzbSoqLCAqKkVtcGlyaWNpc20qKiwgYW5kICoqQ2FwaXRhbGlzbSoqCiogR3JvdXAgNTogKipTdG9pY2lzbSoqLCAqKk5pZXR6c2NoZSoqLCBhbmQgKipDb250aW5lbnRhbCoqCgpUaGUgZ3JvdXBzIG5vdyBzZWVtIHRvIGJlIG1vcmUgYWxpZ25lZCB3aXRoIG15IGluaXRpYWwgaHlwb3RoZXNpcyBhcyBzY2hvb2xzIG9mIHRoZSBzYW1lIHBlcmlvZCBvZiB0aW1lIGFyZSBncm91cGVkIHRvZ2V0aGVyIHN1Y2ggYXMgKipQbGF0byoqIGFuZCAqKkFyaXN0b3RsZSoqLCBvciAqKlJhdGlvbmFsaXNtKiogYW5kICoqRW1waXJpY2lzbSoqLiBUaGUgcmVhc29uICoqU3RvaWNpc20qKiwgKipOaWV0enNjaGUqKiBhbmQgKipDb250aW5lbnRhbCoqIGFyZSBpbiB0aGUgc2FtZSBncm91cCBtaWdodCBiZSBkdWUgdG8gdGhlaXIgdGVuZGVuY3kgb2YgYW50aWNpcGF0aW9uIGFuZCBmZWFyLCB3aGlsZSAqKkZlbWluaXNtKiogbWlnaHQgYmUgYSBzdGFuZGFsb25lIGdyb3VwIGR1ZSB0byBpdHMgZXh0cmVtZSAiam95IiBlbW90aW9uLiBBZ2Fpbiwgb25lIHNob3VsZCBmdXJ0aGVyIHN0dWR5IHRoZSBoaXN0b3J5IG9mIHBoaWxvc29waHkgdG8gYmV0dGVyIHVuZGVyc3RhbmQgdGhlc2UgZ3JvdXBzIGFuZCBiZSBhYmxlIHRvIGV4cGxhaW4gd2h5IG9uZSBzY2hvb2wgaXMgbW9yZSBvciBsZXNzIGxpa2VseSB0byBiZSBzaW1pbGFyIHRvIGFub3RoZXIgc2Nob29sIG9mIHRob3VnaHQuCgojIFdoYXQgZG8gd2UgbGVhcm4gc28gZmFyPwoKKiBUaGUgbW9kZXJuIHNjaG9vbHMgb2YgdGhvdWdodHMgdGVuZCB0byB1c2UgbW9yZSBkZXNjcmlwdGl2ZSB3b3JkcywgYXMgb3Bwb3NlZCB0byB0aGUgYW5jaWVudCBzY2hvb2xzIHdoaWNoIG1vc3RseSB1c2UgZnVuY3Rpb24gd29yZHMgaW4gdGhlaXIgdGV4dHMuCiogVGhlIGF2ZXJhZ2Ugc2VudGVuY2UgbGVuZ3RoIHJlbWFpbnMgYXJvdW5kIDEwMCB3b3Jkcywgd2hpbGUgdGhlIG51bWJlciBvZiBkaXN0aW5jdCB3b3JkcyBkZWNyZWFzZXMgb3ZlciB0aW1lLiBUaGUgbW9kZXJuIHNjaG9vbHMgb2YgdGhvdWdodHMgYXJlIGFsc28gbW9yZSBsaWtlbHkgdG8gdXNlIGxvbmdlciBzZW50ZW5jZXMgYW5kIG1vcmUgZGlzdGluY3Qgd29yZHMgaW4gdGhlaXIgdGV4dHMuCiogVHJ1c3QsIGFudGljaXBhdGlvbiwgYW5kIGpveSBhcmUgdGhlIG1vc3QgZG9taW5hbnQgZW1vdGlvbnMgaW4gcGhpbG9zb3BoaWNhbCB0ZXh0LiBUZXh0cyB3cml0dGVuIGluIHRoZSAxOHRoIGNlbnR1cnkgYXJlIHRoZSBtb3N0IGVtb3Rpb25hbGx5IGNoYXJnZWQuCiogRGlmZmVyZW50IHNjaG9vbHMgb2YgdGhvdWdodHMgbWlnaHQgYmUgbW9yZSBvciBsZXNzIHNpbWlsYXIgdG8gb25lIGFub3RoZXIgZGVwZW5kaW5nIG9uIHRoZWlyIHBlcmlvZCBvZiB0aW1lLCBvcmlnaW4sIHRleHQsIG9yIHNlbnRpbWVudC4KKiBTdHVkeSBwaGlsb3NvcGh5IGJlY2F1c2UgaXQncyBpbnRlcmVzdGluZyE=